%{
#include <stdio.h>
%}

%token INT VOID IDENTIFICADOR IF ELSE RETURN CONSTANTE LITERAL_ALFANUMERICO INC_OP DEC_OP

%union {
  int valor;
  char *nom;
}

%type <valor> CONSTANTE
%type <nom> LITERAL_ALFANUMERICO IDENTIFICADOR

%start unidad_traduccion
%%

/*"unidad_traduccion" es una sucesion de "declaracion_externa" */
unidad_traduccion
	: declaracion_externa				{printf("\n <unidad_traduccion> → <declaracion_externa >");}
	| unidad_traduccion declaracion_externa		{printf("\n <unidad_traduccion> → <unidad_traduccion>  <declaracion_externa>");}
	;

/*"declaracion_externa" puede ser o bien la definicion de una funcion ("definicion_funcion"), o una "declaracion"*/
declaracion_externa
	: definicion_de_funcion				{printf("\n <declaracion_externa> → <definicion_de_funcion>");}
	| declaracion					{printf("\n <declaracion_externa> → <declaracion>");}
	;
/* Declaraciones ---------------------------------------------------------- */

/* Una "declaracion" consta de el especificador de tipo y la lista de declaradores/inicializadores (lista_declarador_inic) */
declaracion
	: especificador_de_tipo ';'				{printf("\n <declaracion> → <especificador_de_tipo> ';'");}
	| especificador_de_tipo lista_declarador_inic ';'	{printf("\n <declaracion> → <especificador_de_tipo> <lista_declarador_inic> ';'");}
	;

/* Solo vamos a implementar el tipo entero */
especificador_de_tipo
	: VOID						{printf("\n <especificador_de_tipo> → VOID");}
	| INT						{printf("\n <especificador_de_tipo> → INT");}
	;

/* Una lista de declaradores/inicializadores es una sucesion de declaradores/inicializadores (declarador_inic) separada por comas */
lista_declarador_inic
	: declarador_inic				{printf("\n <lista_declarador_inic> → <declarador_inic>");}
	| lista_declarador_inic ',' declarador_inic	{printf("\n <lista_declarador_inic> → <lista_declarador_inic> ',' <declarador_inic>");}
	;

/* declarador/inicializador es, o bien un declarador, o bien un declarador mas un inicializador separado por el caracter de asignacion '=' */
declarador_inic
	: declarador					{printf("\n <declarador_inic> → <declarador>");}
	| declarador '=' inicializador			{printf("\n <declarador_inic> → <declarador> '=' <inicializador>");}
	;
/* Un inicializador es una expresion de asignacion */
inicializador
	: expresion_de_asignacion			{printf("\n <inicializador> → <expresion_de_asignacion>");}
	;

/* En nuestra implementacion, un declarador es un declarador directo. Mantenemos esta regla para dejar abierto el diseno para eventualmente incluir punteros */
declarador
	: declarador_directo				{printf("\n <declarador> → <declarador_directo>");}
	;

/* Un declarador directo puede ser un identificador, o una funcion con un cero o un parametro.*/
declarador_directo
	: IDENTIFICADOR					{printf("\n IDENTIFICADOR → %s",$1);printf("\n <declarador_directo> → IDENTIFICADOR");}
	| IDENTIFICADOR '(' declaracion_parametro ')'	{printf("\n IDENTIFICADOR → %s",$1);printf("\n <declarador_directo> → IDENTIFICADOR '(' <declaracion_parametro> ')'");}
	| IDENTIFICADOR '(' ')'				{printf("\n IDENTIFICADOR → %s",$1);printf("\n <declarador_directo> → IDENTIFICADOR '(' ')'");}
	;

/* Una declaracion de parametro esta compuesta por un especificador de tipo, y eventualmente, por un identificador */
declaracion_parametro
	: especificador_de_tipo IDENTIFICADOR		{printf("\n <declaracion_parametro> → <especificador_de_tipo> IDENTIFICADOR");}
	| especificador_de_tipo				{printf("\n <declaracion_parametro> → <especificador_de_tipo>");}
	;

/* Definicion de funcion ------------------------------------*/

/* Definimos una funcion de dos formas: la forma general, consistente en especificador de tipo, declarador, y sentencia compuesta, y la version reducida son especificador de tipo */
definicion_de_funcion
	: especificador_de_tipo declarador sentencia_compuesta	{printf("\n <definicion_de_funcion> → <especificador_de_tipo> <declarador> <sentencia_compuesta>");}
	| declarador sentencia_compuesta			{printf("\n <definicion_de_funcion> → <declarador> <sentencia_compuesta>");}
	;

/* Definimos la sentencia compuesta (o bloque) como una lista de sentencias, o una lista de declaraciones, o una lista de declaraciones seguida por una lista de sentencias */

sentencia_compuesta
	: '{' '}'						{printf("\n <sentencia_compuesta> → '{' '}'");}
	| '{' lista_de_sentencias '}'				{printf("\n <sentencia_compuesta> → '{' <lista_de_sentencias> '}'");}
	| '{' lista_de_declaraciones '}'			{printf("\n <sentencia_compuesta> → '{' <lista_de_declaraciones> '}'");}
	| '{' lista_de_declaraciones lista_de_sentencias '}'	{printf("\n <sentencia_compuesta> → '{' <lista_de_declaraciones> <lista_de_sentencias> '}'");}
	;

/* Una lista de sentencias es una sucesion de sentencias */
lista_de_sentencias
	: sentencia					{printf("\n <lista_de_sentencias> → <sentencia>");}
	| lista_de_sentencias sentencia			{printf("\n <lista_de_sentencias> → <lista_de_sentencias> <sentencia>");}
	;

/* Una lista de declaraciones es una sucesion de declaraciones */
lista_de_declaraciones
	: declaracion					{printf("\n <lista_de_declaraciones> → <declaracion>");}
	| lista_de_declaraciones declaracion		{printf("\n <lista_de_declaraciones> → <lista_de_declaraciones> <declaracion>");}
	;
/* Una sentencia puede ser compuesta, de expresion, de seleccion o de salto */
sentencia
	: sentencia_compuesta				{printf("\n <sentencia> → <sentencia_compuesta>");}
	| sentencia_de_expresion			{printf("\n <sentencia> → <sentencia_de_expresion>");}
	| sentencia_de_seleccion			{printf("\n <sentencia> → <sentencia_de_seleccion>");}
	| sentencia_de_salto				{printf("\n <sentencia> → <sentencia_de_salto>");}
	;

/* Como sentencia de seleccion, solo implementamos el if..else */
sentencia_de_seleccion
	: IF '(' expresion ')' sentencia			{printf("\n <sentencia_de_seleccion> → IF '(' <expresion> ')' <sentencia>");}
	| IF '(' expresion ')' sentencia ELSE sentencia		{printf("\n <sentencia_de_seleccion> → IF '(' <expresion> ')' <sentencia> ELSE <sentencia>");}
	;

/* Como sentencia de salto, implementamos return */
sentencia_de_salto
	: RETURN ';'					{printf("\n <sentencia_de_salto> → RETURN ';'");}
	| RETURN expresion ';'				{printf("\n <sentencia_de_salto> → RETURN <expresion> ';'");}
	;

/* Una sentencia de espresion puede estar vacia */
sentencia_de_expresion
	: ';'						{printf("\n <sentencia_de_expresion> → ';'");}
	| expresion ';'					{printf("\n <sentencia_de_expresion> → <expresion> ';'");}
	;

/* Una expresion es una secuencia de al menos una expresion de asignacion */
expresion
	: expresion_de_asignacion			{printf("\n <expresion> → <expresion_de_asignacion>");}
	| expresion ',' expresion_de_asignacion		{printf("\n <expresion> → <expresion> ',' <expresion_de_asignacion>");}
	;

/* Una expresion de asignacion es una expresion unaria, unida el operador de asignacion y otra expresion de asignacion, que puede ser directamente una expresion de adicion  */
expresion_de_asignacion
	: expresion_de_adicion							{printf("\n <expresion_de_asignacion> → <expresion_de_adicion>");}
	| expresion_unaria operador_de_asignacion expresion_de_asignacion	{printf("\n <expresion_de_asignacion> → <expresion_unaria> <operador_de_asignacion> <expresion_de_asignacion>");}
	; 

/* El operador de asignacion que utilizamos es el igual (=) */
operador_de_asignacion
	: '='								{printf("\n <operador_de_asignacion> → '='");}
	;

/* Una expresion de adicion es una de multplicacion o varias de ellas sumadas o restadas, con asociatividad por la izquierda */
expresion_de_adicion
	: expresion_de_multiplicacion					{printf("\n <expresion_de_adicion> → <expresion_de_multiplicacion>");}
	| expresion_de_adicion '+' expresion_de_multiplicacion		{printf("\n <expresion_de_adicion> → <expresion_de_adicion> '+' <expresion_de_multiplicacion>");}
	| expresion_de_adicion '-' expresion_de_multiplicacion		{printf("\n <expresion_de_adicion> → <expresion_de_adicion> '-' <expresion_de_multiplicacion>");}
	;
/* Una expresion de multiplicacion es una expresion unaria o varias de ellas, multiplicadas, divididas, o halladas su modulo, con asociatividad por la izquierda */
expresion_de_multiplicacion
	: expresion_unaria						{printf("\n <expresion_de_multiplicacion> → <expresion_unaria>");}
	| expresion_de_multiplicacion '*' expresion_unaria		{printf("\n <expresion_de_multiplicacion> → <expresion_de_multiplicacion> '*' <expresion_unaria>");}
	| expresion_de_multiplicacion '/' expresion_unaria		{printf("\n <expresion_de_multiplicacion> → <expresion_de_multiplicacion> '/' <expresion_unaria>");}
	| expresion_de_multiplicacion '%' expresion_unaria		{printf("\n <expresion_de_multiplicacion> → <expresion_de_multiplicacion> '%%' <expresion_unaria>");}
	;
/* Una expresion unaria es una expresion sufija, o un operador unario mas una expresion unaria, o expresiones unarias precedidas por operadores incrementales*/
expresion_unaria
	: expresion_sufija						{printf("\n <expresion_unaria> → <expresion_sufija>");}
	| operador_unario expresion_unaria				{printf("\n <expresion_unaria> → <operador_unario> <expresion_unaria>");}
	| INC_OP expresion_unaria					{printf("\n <expresion_unaria> → INC_OP <expresion_unaria>");}
	| DEC_OP expresion_unaria					{printf("\n <expresion_unaria> → DEC_OP <expresion_unaria");}
	;

/* Los operadores unarios que implementamos son el mas y el menos */
operador_unario
	: '+'								{printf("\n <operador_unario> → '+'");}
	| '-'								{printf("\n <operador_unario> → '-'");}
	;

/* Una expresion sufija es una expresion primaria, una llamada a una funcion, o una expresion sufija seguida de un operador incremental */
expresion_sufija
	: expresion_primaria						{printf("\n <expresion_sufija> → <expresion_primaria>");}
	| IDENTIFICADOR '(' ')'						{printf("\n IDENTIFICADOR → %s",$1);printf("\n <expresion_sufija> → IDENTIFICADOR '(' ')'");}
	| IDENTIFICADOR '(' lista_de_expresiones_de_argumentos ')'	{printf("\n IDENTIFICADOR → %s",$1);printf("\n <expresion_sufija> → IDENTIFICADOR '(' <lista_de_expresiones_de_argumentos> ')'");}
	| expresion_sufija INC_OP					{printf("\n <expresion_sufija> → <expresion_sufija> INC_OP");}
	| expresion_sufija DEC_OP					{printf("\n <expresion_sufija> → <expresion_sufija> DEC_OP");}
	;

/* Una lista de expresiones de argumentos es una lista de expresiones de asignacion */
lista_de_expresiones_de_argumentos
	: expresion_de_asignacion						{printf("\n <lista_de_expresiones_de_argumentos> → <expresion_de_asignacion>");}
	| lista_de_expresiones_de_argumentos ',' expresion_de_asignacion	{printf("\n <lista_de_expresiones_de_argumentos> → <lista_de_expresiones_de_argumentos> ',' <expresion_de_asignacion>");}
	;

/* Una expresion primaria es un identificador, una constante (un numero entero, en nuestro caso) , un literal alfanumerico, o una expresion entre parentesis */
expresion_primaria
	: IDENTIFICADOR							{printf("\n IDENTIFICADOR → %s",$1);printf("\n <expresion_primaria> → IDENTIFICADOR");}
	| CONSTANTE							{printf("\n CONSTANTE → %d",$1);printf("\n <expresion_primaria> → CONSTANTE");}
	| LITERAL_ALFANUMERICO						{printf("\n LITERAL_ALFANUMERICO → %s",$1);printf("\n <expresion_primaria> → LITERAL_ALFANUMERICO");}
	| '(' expresion ')'						{printf("\n <expresion_primaria> → '(' expresion ')'");}
	;

%%
#include <stdio.h>

extern char yytext[];
extern int column;

yyerror(s)
char *s;
{
	fflush(stdout);
	printf("\n%*s\n%*s\n", column, "^", column, s);
	return 1;
}

main ()
{
printf("PLI 2010.\n");
printf("Practicas.\n");
printf("Autores:\n");
printf("- Antonio Balderas Alberico\n");
printf("- Rafael Sanchez Martinez\n");
printf("- Alfonso Sendra Gamero\n\n");
yyparse ();
printf("\n\n\nAnalisis sintactico finalizado.\n");
}

